package com.lagou.sqlsession;

import com.lagou.config.BoundSql;
import com.lagou.pojo.Configuration;
import com.lagou.pojo.MappedStatement;
import com.lagou.utils.*;

import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.*;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

public class SimpleExecutor implements Executor {

    @Override
    public <E> List<E> query(Configuration configuration, MappedStatement mappedStatement, Object... param) throws Exception {
        PreparedStatement preparedStatement = getPreparedStatement(configuration, mappedStatement, param);
        // 执行查询，封装返回结果
        List<Object> list = new ArrayList<>();
        Class<?> resultClass = getClassType(mappedStatement.getResultType());
        ResultSet resultSet = preparedStatement.executeQuery();
        while (resultSet.next()) {
            Object o = resultClass.newInstance();
            // 获取元数据
            ResultSetMetaData metaData = resultSet.getMetaData();
            // 遍历元数据，给结果赋值
            int columnCount = metaData.getColumnCount();
            for (int i = 1; i <= columnCount; i++) {
                String columnName = metaData.getColumnName(i);
                Object value = resultSet.getObject(i);

                // 属性描述器，生成写属性，并赋值
                PropertyDescriptor descriptor = new PropertyDescriptor(columnName, resultClass);
                Method writeMethod = descriptor.getWriteMethod();
                writeMethod.invoke(o, value);
            }
            list.add(o);
        }

        return (List<E>) list;
    }

    @Override
    public Boolean update(Configuration configuration, MappedStatement mappedStatement, Object... param) throws Exception {
        PreparedStatement preparedStatement = getPreparedStatement(configuration, mappedStatement, param);
        return preparedStatement.execute();
    }

    private PreparedStatement getPreparedStatement(Configuration configuration, MappedStatement mappedStatement, Object... param)
            throws Exception {
        // 把xml中的sql 转换为jdbc可执行的sql
        BoundSql boundSql = getBoundSql(mappedStatement.getSql());
        String finalSql = boundSql.getSqlText();

        // 获取连接
        Connection connection = configuration.getDataSource().getConnection();
        PreparedStatement pstm = connection.prepareStatement(finalSql);
        // 给finalSql中的？赋值
        Class<?> parameterClass = getClassType(mappedStatement.getParameterType());
        List<ParameterMapping> parameterMappingList = boundSql.getParameterMappingList();
        for (int i = 0; i < parameterMappingList.size(); i++) {
            // 获取属性名
            ParameterMapping parameterMapping = parameterMappingList.get(i);
            String content = parameterMapping.getContent();
            // 用反射获取值，给pstm中的？赋值
            Field declaredField = parameterClass.getDeclaredField(content);
            declaredField.setAccessible(true);
            Object value = declaredField.get(param[0]);

            pstm.setObject(i + 1, value);
        }
        return pstm;
    }

    private Class<?> getClassType(String className) throws ClassNotFoundException {
        if (className != null)
            return Class.forName(className);
        return null;
    }

    private BoundSql getBoundSql(String sql) {
        ParameterMappingTokenHandler pmth = new ParameterMappingTokenHandler();
        GenericTokenParser parser = new GenericTokenParser("#{", "}", pmth);
        String parse = parser.parse(sql);
        List<ParameterMapping> parameterMappings = pmth.getParameterMappings();
        return new BoundSql(parse, parameterMappings);
    }
}

